home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / vol7n9.arc / RECORDER.ASM < prev    next >
Assembly Source File  |  1988-04-08  |  22KB  |  746 lines

  1.         Page 60,132
  2. ;----------------------------------------------------------------------
  3. ; RECORDER.ASM - A resident program which counts file operations.
  4. ; Run it once to install and initialize it.  Run it again later to
  5. ; view a list of files which have been accessed.  The table
  6. ; shows how many disk accesses have been made while reading and
  7. ; writing to the file.
  8. ;
  9. ; SYNTAX:   RECORDER  [n] [/R]
  10. ; USE   n to specify the maximum number of files (default=200)
  11. ; Use  /R to reset the file table.
  12. ;----------------------------------------------------------------------
  13. CSEG        SEGMENT
  14.         ASSUME    CS:CSEG,DS:NOTHING
  15.         ORG    100H    ;Beginning for .COM programs
  16. START:        JMP INITIALIZE    ;Initialization code is at end
  17.  
  18. ;-----------------------------------------------------------------------
  19. ; Data area used by this program
  20. ;-----------------------------------------------------------------------
  21. COPYRIGHT    DB    "RECORDER 1.0 (c) 1988 Ziff Communications Co."
  22. PROGRAMMER    DB    13,10,"PC Magazine ",254," Tom Kihlken$",1AH
  23.  
  24. FULL_MESS    DB    "*Table is saturated*$"
  25. OLDINT21    DD    ?    ;Old DOS function interrupt vector
  26. OLDINT13    DD    ?    ;Old BIOS disk I/O interrupt vector
  27. NUM_FILES    DW    200    ;Default size of the table
  28. FILE_TABLE_END    DW    ?
  29. LAST_FILE    DW    ?
  30. LAST_HANDLE    DW    ?
  31.  
  32. ;--to help count spaces-012345678901234567890123456789012345678901-----
  33. HEADER        DB    "   File Name  Total   Read  Write   EXEC$"
  34.  
  35. CURRENT_FILE    DB    11 DUP (?)
  36. CURRENT_HANDLE    DW    ?
  37. FUNCTION_ID    DW    ?
  38. BUSY_FLAG    DB    0
  39. BIOS_IO_COUNT    DW    0    ;Counts disk accesses made by BIOS
  40.  
  41. HANDLE_TABLE    EQU    OFFSET INITIALIZE
  42. FILE_TABLE    EQU    HANDLE_TABLE + NUM_HANDLES * 4
  43. NUM_HANDLES    EQU    30
  44. ENTRY_SIZE    EQU    20
  45.  
  46. ;-----------------------------------------------------------------------
  47. ; Interrupt 13 (Diskette I/O) This routine counts disk sector accesses.
  48. ;-----------------------------------------------------------------------
  49. NEWINT13    PROC    FAR
  50.         ASSUME    DS:NOTHING, ES:NOTHING
  51.         CMP    AH,2        ;Is function lower than 2?
  52.         JB    DONT_COUNT    ;If yes, then ignore it
  53.         CMP    AH,4        ;Is function higher than 4?
  54.         JA    DONT_COUNT    ;If yes, then ignore it
  55.         INC    CS:BIOS_IO_COUNT;Add sectors count to total
  56. DONT_COUNT:
  57.         JMP    CS:OLDINT13    ;Continue with disk interrupt
  58. NEWINT13    ENDP
  59.  
  60. ;-----------------------------------------------------------------------
  61. ; Interrupt 21 (DOS functions)  This routine counts file accesses.
  62. ;-----------------------------------------------------------------------
  63. NEWINT21    PROC    FAR
  64.         ASSUME    DS:NOTHING, ES:NOTHING
  65.  
  66.         PUSHF            ;Save callers flags
  67.         STI            ;Get interrupts back on
  68.         CMP    CS:BUSY_FLAG,0    ;Are we busy now?
  69.         JNE    OLD_DOS        ;If busy, just pass it to DOS
  70.         CMP    AH,4BH        ;Is it the EXEC function?
  71.         JE    EXEC        ;Handle EXEC specially
  72.         CMP    AH,0EH        ;Is it below 0EH?
  73.         JBE    OLD_DOS        ;If yes, ignore it
  74.         CMP    AH,31H        ;Is it TSR function?
  75.         JE    OLD_DOS        ;Dont intercept this call
  76.         CMP    AH,45H        ;Is it above 45H?
  77.         JB    INTERCEPT_IT    ;If yes, then ignore it
  78. OLD_DOS:
  79.         POPF            ;Recover callers flags
  80.         CLI
  81.         JMP    CS:OLDINT21    ;Allow interrupt to proceed
  82. EXEC:
  83.         PUSH    AX        ;Save these registers
  84.         PUSH    BX
  85.         PUSH    CX
  86.         PUSH    SI
  87.         PUSH    DI
  88.         PUSH    DS
  89.         PUSH    ES
  90.         MOV    CS:BUSY_FLAG,1    ;Set the busy flag
  91.         MOV    SI,OFFSET PARSE_STRING ;Point to parse routine
  92.         CALL    ENTER_FILENAME    ;Search file table for the file
  93.         JC    EXEC_CONTINUE
  94.         INC    WORD PTR DS:[SI+12]
  95.         INC    WORD PTR DS:[SI+18]
  96. EXEC_CONTINUE:
  97.         MOV    CS:BUSY_FLAG,0    ;Not busy any more
  98.         POP    ES        ;Restore the registers
  99.         POP    DS
  100.         POP    DI
  101.         POP    SI
  102.         POP    CX
  103.         POP    BX
  104.         POP    AX
  105.         JMP    OLD_DOS
  106. INTERCEPT_IT:
  107.         MOV    BUSY_FLAG,1    ;Ignore any other calls
  108.         MOV    FUNCTION_ID,AX    ;Save the function ident.,
  109.         MOV    BIOS_IO_COUNT,0
  110.         CLI
  111.         CALL    CS:OLDINT21    ;Do the DOS function
  112.         STI            ;Reenable interrupts
  113.         PUSHF            ;Save DOS result flags
  114.         PUSH    AX        ;Save these registers
  115.         PUSH    BX
  116.         PUSH    CX
  117.         PUSH    DX
  118.         PUSH    SI
  119.         PUSH    DI
  120.         PUSH    DS
  121.         PUSH    ES
  122.         JNC    CHECK_FUNCTION    ;If no error, continue
  123.         JMP    POP_RET        ;Otherwise just return
  124. CHECK_FUNCTION:
  125.         MOV    CX,FUNCTION_ID
  126.         SUB    CH,0FH        ;Is it 0Fh?
  127.         JZ    READ_FCB
  128.         DEC    CH        ;Is it 10h?
  129.         JZ    WRITE_FCB
  130.         SUB    CH,4        ;Is it 14h?
  131.         JZ    READ_FCB
  132.         DEC    CH        ;Is it 15h?
  133.         JZ    WRITE_FCB
  134.         DEC    CH        ;Is it 16h?
  135.         JZ    READ_FCB
  136.         SUB    CH,0BH        ;Is it 21h?
  137.         JZ    READ_FCB
  138.         DEC    CH        ;Is it 22h?
  139.         JZ    WRITE_FCB
  140.         DEC    CH        ;Is it 23h?
  141.         JZ    READ_FCB
  142.         SUB    CH,4        ;Is it 27h?
  143.         JZ    READ_FCB
  144.         DEC    CH        ;Is it 28h?
  145.         JZ    WRITE_FCB
  146.         JMP    SHORT NOT_FCB_FUNCTN
  147. READ_FCB:
  148.         MOV    BX,14        ;Index for the read column
  149.         JMP    SHORT INC_FCB_COUNT
  150. WRITE_FCB:
  151.         MOV    BX,16        ;Index for the write column
  152. INC_FCB_COUNT:
  153.         MOV    SI,OFFSET PARSE_FCB
  154.         CALL    ENTER_FILENAME    ;Search file table for the file
  155.         JC    JUMP_POP_RET    ;Quit if file not in table
  156.         MOV    AX,BIOS_IO_COUNT;This many disk operations made
  157.         ADD    CS:[SI][BX],AX    ;Add it to the indexed column
  158.         ADD    CS:[SI+12],AX    ;Add it to the total
  159.         JMP    POP_RET
  160.  
  161. ; If it was not a FCB function, see if it was handle I/O
  162.  
  163. NOT_FCB_FUNCTN:
  164.         SUB    CH,14H        ;Is it 3Ch?
  165.         JE    NEW_HANDLE
  166.         DEC    CH        ;Is it 3Dh?
  167.         JE    NEW_HANDLE
  168.         DEC    CH        ;Is it 3Eh?
  169.         JE    WRITE_HANDLE
  170.         DEC    CH        ;Is it 3Fh?
  171.         JE    READ_HANDLE
  172.         DEC    CH        ;Is it 40h?
  173.         JE    WRITE_HANDLE
  174.         SUB    CH,2        ;Is it 42h?
  175.         JE    READ_HANDLE
  176.         SUB    CH,2        ;Is it 44h?
  177.         JE    IO_CONTROL
  178.         JMP    POP_RET
  179. NEW_HANDLE:
  180.         CMP    AX,5        ;Is it a standard handle?
  181.         JGE    GOOD_HANDLE    ;If not, then record it
  182. JUMP_POP_RET:
  183.         JMP    POP_RET        ;Jump to the return
  184. READ_HANDLE:
  185.         MOV    CX,14        ;Index for the read column
  186.         JMP    SHORT INC_DEV_COUNT
  187. IO_CONTROL:
  188.         CMP    CL,2        ;Is it a read request?
  189.         JE    READ_HANDLE    ;Treat it as a read
  190.         CMP    CL,3        ;Is it a write request?
  191.         JNE    JUMP_POP_RET    ;If not read or write, ignore it
  192. WRITE_HANDLE:
  193.         MOV    CX,16        ;Index for the write column
  194. INC_DEV_COUNT:
  195.         CMP    BX,5        ;Is it a standard handle?
  196.         JB    JUMP_POP_RET    ;If it is, then ignore it
  197.         PUSH    CX        ;Put index on the stack
  198.  
  199. ; Now search the handle table for the handle in BX.
  200.  
  201.         CALL    ADD_PSP        ;Add in the current PSP segment
  202.         MOV    DI,HANDLE_TABLE    ;Point to the handle table
  203.         MOV    CX,NUM_HANDLES    ;Search the entire table
  204. HANDLE_LOOP:
  205.         CMP    BX,CS:[DI]    ;Is it a match?
  206.         JE    HANDLE_MATCH    ;If it is, we've found it
  207.         ADD    DI,4        ;If not, look at next entry
  208.         LOOP    HANDLE_LOOP
  209.         POP    BX        ;Restore the stack
  210.         JMP    SHORT POP_RET    ;Return if handle was not found
  211.  
  212. ; If the handle is being closed, then the entry is deleted.
  213.  
  214. HANDLE_MATCH:
  215.         CMP    BYTE PTR FUNCTION_ID+1,3EH ;Closing this file?
  216.         JNE    NOT_CLOSE
  217.         MOV    WORD PTR CS:[DI],0
  218. NOT_CLOSE:
  219.         MOV    DI,CS:[DI+2]    ;Get pointer to file table entry
  220.         POP    BX        ;Get the index back
  221.         MOV    AX,BIOS_IO_COUNT ;Get the sector count
  222.         ADD    CS:[DI][BX],AX    ;Add it to selected column
  223.         ADD    CS:[DI+12],AX    ;And also to the total column
  224.         JMP    SHORT POP_RET
  225. GOOD_HANDLE:
  226.         MOV    CURRENT_HANDLE,AX    ;Save the handle
  227.         MOV    SI,OFFSET PARSE_STRING  ;Point to parse routine
  228.         CALL    ENTER_FILENAME    ;Add the file to the table
  229.         JC    JUMP_POP_RET    ;If table is full, return
  230.         MOV    AX,BIOS_IO_COUNT;Get number of sectors
  231.         ADD    DS:[SI+12],AX    ;Add to the total column
  232.         ADD    DS:[SI+14],AX    ;Add to the read column
  233.  
  234. ; Now enter this new handle to the handle table
  235.  
  236.         MOV    DI,LAST_HANDLE    ;Get location of last entry
  237.         ADD    DI,4        ;Advance it one position
  238.         CMP    DI,HANDLE_TABLE+NUM_HANDLES*4
  239.         JNE    KEEP_GOING
  240.         MOV    DI,HANDLE_TABLE
  241. KEEP_GOING:
  242.         MOV    LAST_HANDLE,DI      ;Now this is the last handle
  243.         MOV    BX,CURRENT_HANDLE ;Get handle back
  244.         CALL    ADD_PSP        ;Add in the current PSP segment
  245.         MOV    CS:[DI],BX    ;Store the handle
  246.         MOV    CS:[DI+2],SI    ;Store location in file table
  247. POP_RET:
  248.         MOV    CS:BUSY_FLAG,0    ;Not busy any more
  249.         POP    ES        ;Restore all registers
  250.         POP    DS
  251.         POP    DI
  252.         POP    SI
  253.         POP    DX
  254.         POP    CX
  255.         POP    BX
  256.         POP    AX
  257.         POPF            ;Recover DOS result flags
  258.         STI            ;Return with interrupts on
  259.         RET    2        ;Return with these flags
  260. NEWINT21    ENDP
  261.  
  262. ;-----------------------------------------------------------------------
  263. ; ENTER_FILENAME adds the file at DS:DX to the table.
  264. ; It returns with DS:SI pointing to the entry.  If CF=1, then the name
  265. ; was not in the table and no more entries could be added.
  266. ;-----------------------------------------------------------------------
  267.         ASSUME    DS:NOTHING, ES:CSEG
  268. ENTER_FILENAME    PROC    NEAR
  269.         CLD            ;String moves forward
  270.         PUSH    CS        ;Set up the ES register
  271.         POP    ES
  272.  
  273.         MOV    DI,OFFSET CURRENT_FILE
  274.         MOV    AL," "        ;Fill with blanks
  275.         MOV    CX,11        ;11 letters in name
  276.         REP    STOSB
  277.  
  278.         CALL    SI        ;Call the parse routine
  279.  
  280. ; Now search the file table for the current filename
  281.         CLD
  282.         PUSH    CS
  283.         POP    DS        ;Set DS to this segment
  284.         ASSUME    DS:CSEG
  285.         MOV    CX,NUM_FILES    ;Try all entries
  286.         MOV    SI,FILE_TABLE    ;Setup for a string compare
  287. SEARCH_LOOP:
  288.         MOV    DI,OFFSET CURRENT_FILE
  289.         PUSH    CX        ;Save the loop counter
  290.         PUSH    SI        ;Save the source also
  291.         MOV    CX,11        ;Compare 11 characters
  292.         REPE    CMPSB        ;Do they all match?
  293.         POP    SI
  294.         POP    AX        ;Recover loop counter
  295.         JCXZ    CLEAR_RETURN    ;If matched, return CF=0
  296.         ADD    SI,ENTRY_SIZE    ;Point to next name in table
  297.         MOV    CX,AX        ;Get loop counter back to CX
  298.         LOOP    SEARCH_LOOP
  299.         MOV    DI,LAST_FILE    ;Get location of last entry
  300.         CMP    DI,-1        ;Is table saturated?
  301.         JE    TABLE_FULL    ;If yes, then return
  302.  
  303.         MOV    CX,NUM_FILES    ;Loop through file table
  304. FIND_OLDEST:
  305.         ADD    DI,ENTRY_SIZE    ;Point to next entry in table
  306.         CMP    DI,FILE_TABLE_END
  307.         JB    NO_WRAP
  308.         MOV    DI,FILE_TABLE
  309. NO_WRAP:
  310.         MOV    AX,[DI+12]    ;Get total for this record
  311.         CMP    AX,1        ;Is it less than one?
  312.         JBE    FOUND_OLDEST    ;If it is, then we'll use it
  313.         LOOP    FIND_OLDEST    ;Search entire table for a space
  314.         MOV    LAST_FILE,-1    ;If none found, table is full
  315. TABLE_FULL:
  316.         STC            ;Carry flag indicates table full
  317.         RET
  318.  
  319. ; At this point ES:DI points to newest table entry
  320.  
  321. FOUND_OLDEST:
  322.         MOV    LAST_FILE,DI
  323.         PUSH    DI
  324.         CLD            ;String moves forward
  325.         MOV    SI,OFFSET CURRENT_FILE
  326.         MOV    CX,11        ;Copy the filename to table
  327.         REP    MOVSB        ;Move the string in
  328.         XOR    AX,AX
  329.         INC    DI        ;Point to the totals column
  330.         STOSW            ;Set total column to zero
  331.         STOSW            ;Set open column to zero
  332.         STOSW            ;Set read column to zero
  333.         STOSW            ;Set write column to zero
  334.         STOSW
  335.         POP    SI
  336. CLEAR_RETURN:
  337.         CLC            ;Indicates sucessful return
  338.         RET
  339. ENTER_FILENAME    ENDP
  340.  
  341. ;-----------------------------------------------------------------------
  342. ; This subroutine parses a filename from the FCB at DS:DX
  343. ;-----------------------------------------------------------------------
  344.         ASSUME    DS:NOTHING, ES:CSEG
  345. PARSE_FCB    PROC    NEAR
  346.         INC    DX        ;Point to filename in FCB
  347.         MOV    SI,DX        ;Get address in index register
  348.         ADD    SI,8        ;Point to file extension
  349.         MOV    DI,OFFSET CURRENT_FILE+8 ;DI Points to extension
  350.         MOV    CX,3
  351. COPY_EXT_1:
  352.         LODSB            ;Get a letter of the extension
  353.         CALL    UPPER_CASE    ;Make it upper case
  354.         STOSB            ;Store it in current file
  355.         LOOP    COPY_EXT_1
  356.         SUB    SI,3
  357.         JMP    SHORT COPY_NAME    ;Finish copying the name
  358.         RET
  359. PARSE_FCB    ENDP
  360.  
  361. ;-----------------------------------------------------------------------
  362. ;This routine parses an ASCII filename from DS:DX and places it at
  363. ; CURRENT_FILE
  364. ;-----------------------------------------------------------------------
  365. PARSE_STRING    PROC    NEAR
  366.         ASSUME    DS:NOTHING, ES:CSEG
  367.         MOV    SI,DX        ;Get address in index register
  368. LOOK_FOR_DOT:
  369.         LODSB            ;Next letter of name
  370.         OR    AL,AL        ;Is it the last letter
  371.         JZ    COPY_NAME1 ;If yes, begin to copy the name
  372.         CMP    AL,"."        ;Is this the dot?
  373.         JNE    LOOK_FOR_DOT
  374. GOT_THE_DOT:
  375.         PUSH    SI        ;Now SI points to the extension
  376.         MOV    DI,OFFSET CURRENT_FILE+8 ;DI points to extension
  377.         MOV    CX,3
  378. COPY_EXTENSION:
  379.         LODSB            ;Next letter of the extension
  380.         OR    AL,AL        ;Is it the last letter?
  381.         JZ    END_COPY
  382.         CALL    UPPER_CASE    ;Convert letter to upper case
  383.         STOSB            ;And store it
  384.         LOOP    COPY_EXTENSION
  385. END_COPY:
  386.         POP    SI        ;Recover location of name
  387. COPY_NAME1:
  388.         DEC    SI
  389. COPY_NAME:
  390.         DEC    SI
  391.         STD            ;Copy name right to left
  392.         MOV    CX,8        ;Eight letters in filename
  393.         MOV    DI,OFFSET CURRENT_FILE+7 ;Point to end of name
  394. NAME_LOOP:
  395.         CMP    SI,DX        ;At start of name yet?
  396.         JB    PARSE_DONE    ;If yes, then quit copying
  397.         LODSB            ;Get letter of name
  398.         CMP    AL,"\"        ;At path specification?
  399.         JE    PARSE_DONE    ;If yes, then quit copying
  400.         CMP    AL,"/"        ;At path specification?
  401.         JE    PARSE_DONE    ;If yes, then quit copying
  402.         CMP    AL,":"        ;At drive specification?
  403.         JE    PARSE_DONE    ;If yes, then quit copying
  404.         CMP    AL," "        ;Is this letter a space?
  405.         JE    SKIP_SPACE    ;Don't copy any spaces
  406.         CALL    UPPER_CASE    ;Convert letters to upper case
  407.         STOSB            ;Store the letter
  408. SKIP_SPACE:
  409.         CMP    SI,0FFFFH    ;Did SI wrap around segment?
  410.         JE    PARSE_DONE    ;If yes, then quit copying
  411.         LOOP    NAME_LOOP ;Loop through entire name
  412. PARSE_DONE:
  413.         RET            ;Done parsing the name
  414. PARSE_STRING    ENDP
  415.  
  416. ;-----------------------------------------------------------------------
  417. ; This subroutine converts the letter in AL to upper case.
  418. ;-----------------------------------------------------------------------
  419. UPPER_CASE    PROC    NEAR
  420.         ASSUME    DS:NOTHING, ES:NOTHING
  421.         CMP    AL,"a"        ;Is it lower case?
  422.         JB    NO_CHANGE    ;If not, don't change it
  423.         CMP    AL,"z"        ;Is it a letter?
  424.         JA    NO_CHANGE    ;If not, don't change it
  425.         AND    AL,11011111B    ;This convert to upper case
  426. NO_CHANGE:    RET
  427. UPPER_CASE    ENDP
  428.  
  429. ;-----------------------------------------------------------------------
  430. ; This subroutine adds the current PSP segment address to the handle
  431. ; in BX.  This creates a unique number for each open handle.
  432. ;-----------------------------------------------------------------------
  433. ADD_PSP        PROC    NEAR
  434.         ASSUME    DS:NOTHING, ES:NOTHING
  435.         PUSH    BX        ;Save the starting handle
  436.         MOV    AH,51H        ;Get current PSP
  437.         INT    21H
  438.         POP    AX        ;Get back starting handle
  439.         ADD    BX,AX        ;And add it to the PSP
  440.         RET
  441. ADD_PSP        ENDP
  442.  
  443. ;-----------------------------------------------------------------------
  444. ; This subroutine zeros out the file and handle tables.
  445. ; on entry DS points to the tables segment.
  446. ;-----------------------------------------------------------------------
  447. RESET_TABLE    PROC    NEAR
  448.         ASSUME    DS:NOTHING, ES:NOTHING
  449.         PUSH    DS
  450.         POP    ES
  451.         MOV    DI,FILE_TABLE
  452.         MOV    CX,DS:NUM_FILES
  453.         XOR    AX,AX
  454. ZERO_FILES:
  455.         STOSW            ;Erase the old filename
  456.         ADD    DI,10
  457.         STOSW            ;Zero the total count
  458.         ADD    DI,ENTRY_SIZE-14
  459.         LOOP    ZERO_FILES
  460.         MOV    DI,HANDLE_TABLE    ;Point to the handle table
  461.         MOV    CX,NUM_HANDLES    ;Number of entries in it.
  462. ZERO_HANDLES:
  463.         XOR    AX,AX
  464.         STOSW
  465.         MOV    AX,FILE_TABLE
  466.         STOSW
  467.         LOOP    ZERO_HANDLES    ;Zero the handle table entries
  468.         MOV    LAST_FILE,FILE_TABLE
  469.         MOV    LAST_HANDLE,HANDLE_TABLE
  470.         RET
  471. RESET_TABLE    ENDP
  472.  
  473. ;-----------------------------------------------------------------------
  474. ; To install, store existing interrupt vectors and replace them with the
  475. ; new ones.  Then exit and remain resident.
  476. ;-----------------------------------------------------------------------
  477. INSTALL:
  478.         ASSUME    CS:CSEG, DS:CSEG, ES:NOTHING
  479.         CALL    LOAD_PARAMS
  480.         JCXZ    NO_DIGITS
  481.         XOR    AX,AX        ;Clear AX for the total
  482. GET_DIGIT:
  483.         MOV    BL,DS:[SI]    ;Get next letter
  484.         SUB    BL,30H        ;Convert ascii to integer
  485.         JC    NOT_A_DIGIT    ;Was it below a 0?
  486.         CMP    BL,9        ;Was it above a 9?
  487.         JA    NOT_A_DIGIT    ;Ignore if not 0-9
  488.         MOV    BH,10
  489.         MUL    BH        ;Times 10 for next digit
  490.         XOR    BH,BH
  491.         ADD    AX,BX        ;Add in the new digit
  492. NOT_A_DIGIT:
  493.         INC    SI
  494.         LOOP    GET_DIGIT    ;Look at all characters
  495.         OR    AX,AX        ;Did we get anything
  496.         JZ    NO_DIGITS
  497.         CMP    AX,2000        ;Above the upper limit?
  498.         JBE    SIZE_OK
  499.         MOV    AX,2000
  500. SIZE_OK:
  501.         MOV    NUM_FILES,AX
  502. NO_DIGITS:
  503.                MOV    AX,3513H    ;Get BIOS disk I/O vector
  504.         INT    21H
  505.         MOV    WORD PTR [OLDINT13]  ,BX
  506.         MOV    WORD PTR [OLDINT13+2],ES
  507.         MOV    DX, OFFSET NEWINT13
  508.         MOV    AX, 2513H
  509.  
  510.         INT    21H        ;DOS function to change vector
  511.                MOV    AX,3521H    ;Get DOS function vector
  512.         INT    21H
  513.         MOV    WORD PTR [OLDINT21]  ,BX
  514.         MOV    WORD PTR [OLDINT21+2],ES
  515.         MOV    DX, OFFSET NEWINT21
  516.         MOV    AX, 2521H
  517.         INT    21H        ;DOS function to change vector
  518.  
  519. ;-----------------------------------------------------------------------
  520. ; Deallacote our copy of the enviornment.
  521. ; Exit using INT 27H. Leave code and space for the tables resident.
  522. ;-----------------------------------------------------------------------
  523.  
  524.         CALL    RESET_TABLE    ;Clear out the file table
  525.         MOV    AX,DS:[002CH]    ;Get segment of enviornment
  526.         MOV    ES,AX        ;Put it into ES
  527.         MOV    AH,49H        ;Release enviornment segment
  528.         INT    21H
  529.  
  530.         MOV    AX,NUM_FILES    ;Get number of files
  531.         MOV    BX,ENTRY_SIZE    ;Times size of each entry
  532.         MUL    BX
  533.         ADD    AX,FILE_TABLE    ;Add in beginning of table
  534.         MOV    FILE_TABLE_END,AX
  535.         ADD    AX,15
  536.         MOV    CL,4
  537.         SHR    AX,CL
  538.         MOV    DX,AX        ;Leave this much resident
  539.         MOV    AX,3100H
  540.         INT    21H        ;Terminate and stay resident
  541.  
  542. ;-----------------------------------------------------------------------
  543. ; Here is the code used to initialize RECORDER.COM.  First determine
  544. ; if RECORDER is already installed.
  545. ;-----------------------------------------------------------------------
  546.         ASSUME    CS:CSEG, DS:CSEG, ES:NOTHING
  547. EVEN                    ;Align to an even byte boundry
  548.  
  549. INITIALIZE:
  550.         ASSUME    DS:CSEG, ES:NOTHING
  551.         MOV    DX,OFFSET COPYRIGHT
  552.         CALL    STRING_CRLF    ;Display the string
  553.  
  554. ; Search for a previously installed copy of RECORDER
  555.  
  556.         NOT    WORD PTR START    ;Modify to avoid false match
  557.         XOR    BX,BX        ;Start search at segment zero
  558.         MOV    AX,CS        ;Compare to this code segment
  559. NEXT_SEGMENT:
  560.         INC    BX        ;Look at next segment
  561.         CMP    AX,BX        ;Until reaching this segment
  562.         MOV    ES,BX
  563.         JNE    NOT_FOUND
  564.         JMP    INSTALL
  565. NOT_FOUND:
  566.         MOV    SI,OFFSET START    ;Setup to compare strings
  567.         MOV    DI,SI
  568.         MOV    CX,16        ;16 bytes must match
  569.         REP    CMPSB        ;Compare DS:SI to ES:DI
  570.         OR    CX,CX
  571.         JNZ    NEXT_SEGMENT    ;If no match, try next segment
  572.  
  573. ; When all 16 bytes match, an installed copy already exists and
  574. ; ES points to resident code segment. Display the file table
  575.  
  576.         PUSH    ES
  577.         POP    DS        ;DS also points to table
  578.         ASSUME    DS:NOTHING, ES:NOTHING
  579.  
  580.         MOV    DI,FILE_TABLE    ;Point to the table
  581.         MOV    CX,DS:NUM_FILES    ;Number of entries in table
  582. ZERO_LOOP:
  583.         MOV    BYTE PTR [DI+11],0 ;Zero the displayed byte
  584.         ADD    DI,ENTRY_SIZE    ;Move to next entry
  585.         LOOP    ZERO_LOOP    ;Do entire table
  586.  
  587.         CALL    NEW_LINE
  588.         MOV    DX,OFFSET HEADER;Point to header text
  589.         CALL    STRING_CRLF    ;Display the string
  590.         MOV    CX,DS:NUM_FILES    ;Number of entries in table
  591. FILE_LOOP:
  592.         PUSH    CX
  593.         MOV    DI,FILE_TABLE    ;Point to the table
  594.         XOR    AX,AX
  595.         MOV    CX,DS:NUM_FILES    ;Number of entries in table
  596. FIND_BIGGEST:
  597.         CMP    [DI+12],AX
  598.         JBE    NOT_BIGGER
  599.         CMP    BYTE PTR [DI+11],0
  600.         JNE    NOT_BIGGER
  601.         MOV    SI,DI
  602.         MOV    AX,[DI+12]
  603. NOT_BIGGER:
  604.         ADD    DI,ENTRY_SIZE
  605.         LOOP    FIND_BIGGEST
  606.  
  607.         CMP    BYTE PTR [SI+11],1
  608.         JE    LAST_ONE
  609.         MOV    BYTE PTR [SI+11],1
  610.         MOV    DX,SI
  611.         ADD    SI,12
  612.         CMP    WORD PTR [SI],0
  613.         JZ    LAST_ONE
  614.         MOV    AH,40H
  615.         MOV    BX,1
  616.         MOV    CX,8        ;8 letters in name
  617.         INT    21H
  618.         PUSH    DX
  619.         MOV    AL,"."        ;Display a dot
  620.         CALL    DISPLAY_CHAR
  621.         POP    DX
  622.         ADD    DX,8        ;Now point to extension
  623.         MOV    AH,40H
  624.         MOV    CX,3        ;3 letters in extension
  625.         INT    21H
  626.         LODSW
  627.         PUSH    AX        ;Save the total
  628.         CALL    NUMBER_OUT    ;Display the totals column
  629.         LODSW
  630.         CALL    NUMBER_OUT
  631.         LODSW
  632.         CALL    NUMBER_OUT
  633.         LODSW
  634.         CALL    NUMBER_OUT
  635.         CALL    NEW_LINE
  636.         POP    AX        ;Recover the total count
  637.         POP    CX
  638.         LOOP    FILE_LOOP
  639.         CMP    AX,2        ;Was the last total less than 2?
  640.         JB    LAST_ONE    ;If yes, table is not full yet.
  641.         CALL    NEW_LINE
  642.         MOV    DX,OFFSET FULL_MESS
  643.         CALL    STRING_CRLF    ;Display the string
  644. LAST_ONE:
  645.         CALL    LOAD_PARAMS
  646.         JCXZ    NO_PARAMS
  647. SCAN_PARAMS:
  648.         MOV    AL,CS:[SI]
  649.         OR    AL,32        ;Convert it to lower case
  650.         CMP    AL,"r"        ;Is it the R parameter?
  651.         JE    SLASH_R        ;If yes, then reset the table
  652.         INC    SI
  653.         LOOP    SCAN_PARAMS    ;Look at all parameters
  654. NO_PARAMS:
  655.         MOV    AX,4C00H
  656.         INT    21H
  657. SLASH_R:
  658.         CALL    RESET_TABLE
  659.         JMP    NO_PARAMS
  660.  
  661. ;-----------------------------------------------------------------------
  662. ; NUMBER_OUT Outputs the number in AX to the standard output device
  663. ;-----------------------------------------------------------------------
  664. NUMBER_OUT    PROC    NEAR
  665.         PUSH    AX        ;Save the number
  666.         MOV    AL," "        ;Send a space
  667.                 CALL    DISPLAY_CHAR    ;Write the character
  668.         MOV    AL," "        ;Send another space
  669.                 CALL    DISPLAY_CHAR    ;Write the character
  670.         POP    AX
  671.         XOR    CX,CX        ;Indicates no digit yet
  672.  
  673.         MOV    BX,10000    ;Get 10000's digit
  674.         CALL    DIVIDE_OUT    ;Display it
  675.         MOV    BX,1000        ;Get 1000's digit
  676.         CALL    DIVIDE_OUT    ;Display it
  677.         MOV    BX,100        ;Get 100's digit
  678.         CALL    DIVIDE_OUT    ;Display it
  679.         MOV    BX,10        ;Get 10's digit
  680.         CALL    DIVIDE_OUT    ;Display it
  681.  
  682.         ADD    AL,30H        ;Get 1's digit
  683.                 CALL    DISPLAY_CHAR    ;Display the last character
  684.         RET
  685. NUMBER_OUT    ENDP
  686.  
  687. ;-----------------------------------------------------------------------
  688. ; This divides AX by BX and displays the result. Remainder is in AX.
  689. ;-----------------------------------------------------------------------
  690. DIVIDE_OUT    PROC    NEAR
  691.         XOR    DX,DX
  692.         DIV    BX        ;Divide to get this digit
  693.                 PUSH    DX        ;Save the remainder
  694.                 OR    CX,AX
  695.         OR    CX,CX        ;Any digits yet?
  696.         JNZ    NOT_A_SPACE
  697.         MOV    AL," "-30H
  698. NOT_A_SPACE:
  699.         ADD    AL,30H        ;Convert it to ASCII
  700.         PUSH    CX
  701.         CALL    DISPLAY_CHAR    ;Write the character
  702.         POP    CX
  703.         POP    AX        ;Get the remainder back
  704.         RET
  705. DIVIDE_OUT    ENDP
  706.  
  707. ;-----------------------------------------------------------------------
  708. ; DISPLAY_CHAR outputs the character in AL to the standard output device
  709. ;-----------------------------------------------------------------------
  710. DISPLAY_CHAR    PROC    NEAR
  711.         MOV    DL,AL        ;Get the character into DL
  712.         MOV    AH,02        ;DOS string output function
  713.         INT    21H
  714.         RET
  715. DISPLAY_CHAR    ENDP
  716.  
  717. ;-----------------------------------------------------------------------
  718. ; STRING_CR displays a string followed by a CR and LF
  719. ; Entry point NEW_LINE displays only the CR and LF
  720. ;-----------------------------------------------------------------------
  721. STRING_CRLF    PROC    NEAR
  722.         MOV    AH,9        ;Display string function
  723.         INT    21H
  724. NEW_LINE:
  725.         MOV    AL,13        ;The carriage return
  726.         CALL    DISPLAY_CHAR    ;Send it
  727.         MOV    AL,10        ;The line feed
  728.         CALL    DISPLAY_CHAR    ;Send it
  729.         RET
  730. STRING_CRLF    ENDP
  731.  
  732. ;-----------------------------------------------------------------------
  733. ; This subroutine sets DI to the command line and CX to the byte count
  734. ;-----------------------------------------------------------------------
  735. LOAD_PARAMS    PROC    NEAR
  736.         MOV    SI,80H        ;Point to parameter area
  737.         MOV    CL,CS:[SI]    ;Get number of chars into CL
  738.         XOR    CH,CH        ;Make it a word
  739.         INC    SI        ;Point to first character
  740.         CLD            ;String searchs forward
  741.         RET
  742. LOAD_PARAMS    ENDP
  743.  
  744. CSEG        ENDS
  745.         END    START
  746.